/**
 * Projeto final de Programacao Concorrente.
 * Prof. Dr. Julio Estrella
 * 
 * Geracao aleatoria de palavras.
 * 
 * Grupo 07 - Turma B
 * Fabio de Albuquerque Dela Antonio 6792558
 * Leonardo Henrique Omoto 6793160
 * Pedro Paulo Canto Martucci 6793100
 * 
 * hashMap.cpp
 */

#include "hashMap.h"

/**
 * Funcao para inicializar base de dados de palavras
 * (com base nas palavras do arquivo)
 */
hashMap::hashMap(const char *filename)
{
    found = 0;

    bool first = true; 
    char token;
    string word;
    
    ifstream indata;
    
    /* Abre arquivo com as palavras */
    indata.open(filename);

    /* Verifica se arquivo foi aberto */
    if(!indata.is_open()) {
       cerr << "Impossivel abrir arquivo de palavras!\n";
       exit(1);
    }
    
    /* Percorre arquivo, obtendo as palavras e armazenando na base de dados */
    while(!indata.eof()) {
        
        /* Obtem caractere do arquivo */
        indata.get(token);

        /* Se token (caractere) for valido, adiciona em uma palavra. */
        if((token >= 'a' && token <= 'z') || (token >= 'A' && token <= 'Z')) {
            word.push_back(tolower(token));
            first = false;
        }

        /* Se nao for valido e nao e primeiro caractere de palavra, entao completa uma palavra */
        else if(!first) {

            if(word.size() != 0) {

                /* Se a palavra for menor do que MAX_LENGHT_WORD entao ela 
                 * sera inserida, caso contrario ela sera particionada e suas
                 * partes serao inseridas. 
                 */
                if(word.size() <= MAX_LENGHT_WORD)
                    Words.insert(pair<string, int>(word, NOT_FOUND));
                else {
                    #ifdef SPLIT       
                    splitWord(word);
                    #endif
                }

            }
            
            word.erase();
        }
    }
}

/**
 * Verifica se palavra gerada corresponde a alguma palavra do arquivo
 */
int hashMap::check(string word)
{

    static int k = 0;

    map<string,int>::iterator it;
    
    /* Busca palavra */
    it = Words.find(word);

    /* Se encontrou a palavra. */
    if(it != Words.end())
    {
        /* Se palavra nao foi encontrada anteriormente, marca como encontrada. */   
        if(it->second == NOT_FOUND)
        {
            /* Marca palavra como encontrada e incrementa contador de palavras encontradas */
            it->second = FOUND;
            found++;
        }
        
    } 

    return found;
}

/**
 * Quebra palavras de tamanho maior do que MAX_LENGHT_WORD
 * em palavras de ate MAX_LENGHT_WORD caracteres.
 */
void hashMap::splitWord(string word)
{
    int lenght = word.size();
    
    string str1, str2;

    /* Divide palavra em 2 */
    str1.append(word,0,lenght/(int)2);
    str2.append(word,lenght/(int)2,lenght); 

    /* Insere as metades da palavra na base de dados (hashMap)
     * se estas metades forem menores que MAX_LENGHT_WORD.
     * Caso contrario, particiona novamente. 
     */
    if(str1.size() <= MAX_LENGHT_WORD)
        Words.insert(pair<string,int>(str1,NOT_FOUND));       
    else
        splitWord(str1);
    
    if(str2.size() <= MAX_LENGHT_WORD)
        Words.insert(pair<string,int>(str2,NOT_FOUND));
    else
        splitWord(str2);
}

/**
 * Obtem o numero de palavras na base de dados (hashMap).
 */
int hashMap::getWords() {
    return Words.size();
}

/**
 * Verifica se o numero de palavras encontradas
 * corresponde ao numero total de palavras da base.
 */
bool hashMap::done() {
    return (found == getWords());
}

/**
 * Retorna a palavra do indice passado
 **/
string hashMap::getWord(map<string,int>::iterator index)
{

    return index->first;
    
}

/**
 * Retorna a palavra do indice passado
 **/
map<string,int>::iterator hashMap::getEnd()
{

    return Words.end();
    
}
/**
 * Retorna a palavra do indice passado
 **/
map<string,int>::iterator hashMap::getBegin()
{
    

    return Words.begin();
    
}
